#include "stdafx.h"
#include "UsbHid.h"

#pragma comment(lib,"hid.lib")
#pragma comment(lib,"Setupapi.lib")

UsbHid *UsbHid::head;

UsbHid::UsbHid(HDEVINFO devinfo,SP_DEVICE_INTERFACE_DATA *devdata){
	uint n;
	SetupDiGetDeviceInterfaceDetail(devinfo,devdata,NULL,0,&n,NULL);
	SP_DEVICE_INTERFACE_DETAIL_DATA *detail=
		(PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED,n);
	if(detail){
		detail->cbSize=sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
		SetupDiGetDeviceInterfaceDetail(devinfo,devdata,detail,n,&n,NULL);
		device=CreateFile(detail->DevicePath,GENERIC_READ|GENERIC_WRITE,
			FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL,NULL);
		if(device!=INVALID_HANDLE_VALUE){
			HIDD_ATTRIBUTES attr;
			attr.Size=sizeof(attr);
			HidD_GetAttributes(device,&attr);
			if((attr.VendorID==HID_VENDOR)&&(attr.ProductID==HID_PRODUCT)){
				HidD_GetSerialNumberString(device,serialNum,MAX_PATH);
				thread=CreateThread(NULL,0,threadProc,this,CREATE_SUSPENDED,&n);
				LocalFree(detail);
				return;
			}
			CloseHandle(device);
		}
		LocalFree(detail);
	}
	device=INVALID_HANDLE_VALUE;
	throw(0);
}
UsbHid::~UsbHid(){
	if(thread){
		TerminateThread(thread,0);
		CloseHandle(thread);
	}
	if(device!=INVALID_HANDLE_VALUE)
		CloseHandle(device);
}

void UsbHid::closeAll(void){
	UsbHid *n,*p;
	for(p=head;p;){
		n=p->link;
		delete p;
		p=n;
	}
	head=0;
}
uint UsbHid::getReport(void *buffer,uint length){
	uint len;
	ReadFile(device,buffer,length,&len,0);
	return len;
}
uint UsbHid::localTick(void){
	SYSTEMTIME	st;
	FILETIME	ft;
	GetLocalTime(&st);
	SystemTimeToFileTime(&st,&ft);
	return(uint)((((__int64)ft.dwHighDateTime<<32)+ft.dwLowDateTime)/10000000
		-11644473600);
}
void UsbHid::openAll(HIDCREATE hidCreate){
	GUID guid;
	HidD_GetHidGuid(&guid);
	HDEVINFO info=SetupDiGetClassDevs(&guid,NULL,NULL,
		DIGCF_PRESENT|DIGCF_INTERFACEDEVICE);
	if(info==INVALID_HANDLE_VALUE)
		return;

	SP_DEVICE_INTERFACE_DATA dat;
	dat.cbSize=sizeof(dat);
	for(int i=0;SetupDiEnumDeviceInterfaces(info,NULL,&guid,i,&dat);i++){
		try{
			UsbHid *o=hidCreate(info,&dat);
			ResumeThread(o->thread);
			o->link=head;
			head=o;
		}catch(int){
		}
		dat.cbSize=sizeof(dat);
	}   
	SetupDiDestroyDeviceInfoList(info);
}
PTSTR UsbHid::serialNumber(void){
	return head?head->serialNum:0;
}
void UsbHid::sendReport(void *data,uint length){
	uint len;
	WriteFile(device,data,length,&len,0);
}
uint UsbHid::threadEntry(void){
	return 0;
}
uint WINAPI UsbHid::threadProc(void *param){
	return((UsbHid*)param)->threadEntry();
}